package com.hongfasoft.util;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hongfasoft.wx.message.Article;
import com.hongfasoft.wx.message.BaseMessage;
import com.hongfasoft.wx.message.JSONBaseMessage;
import com.hongfasoft.wx.message.JSONNewsMessage;
import com.hongfasoft.wx.message.JsonArticle;
import com.hongfasoft.wx.message.MessageUtil;
import com.hongfasoft.wx.message.NewsMessage;
import com.hongfasoft.wx.pojo.Menu;
import com.hongfasoft.wx.pojo.UserInfo;
import com.hongfasoft.wx.service.AccessToken;

/**
 * 
 * 类描述：公众平台通用接口工具类
 * 
 * @author 王涛
 * @date 2014年12月7日
 */
public class WeixinUtil
{
	private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);

	// 第三方用户唯一凭证
	public static final String partner = "1231775202", partnerkey = "899318";
	private static final String appId = "wx4fbfd12de50a98c7";
	public static final String hostURL = "http://wx.zjldl.cn/AJZTJWeiWeb/";
	public static final String oauth2URL = "https://open.weixin.qq.com/connect/oauth2/authorize";
	// 第三方用户唯一凭证密钥
	private static final String appSecret = "a141a193025a3b4f91b10572d7946651";
	// 获取access_token的接口地址（GET） 限200（次/天）
	public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret="
			+ appSecret;
	public final static String wxdownPath = "downMedia";

	public static String getAppid()
	{
		return appId;
	}

	public static String getAppsecret()
	{
		return appSecret;
	}

	/**
	 * 获取access_token
	 * 
	 * @param appid
	 *            凭证
	 * @param appsecret
	 *            密钥
	 * @return
	 */
	protected synchronized static AccessToken getAccessToken()
	{
		AccessToken accessToken = null;

		String requestUrl = access_token_url;
		JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
		int count = 0;
		// 如果请求成功
		while (count < 3 && null == jsonObject)
		{
			jsonObject = httpRequest(requestUrl, "GET", null);
			count++;
		}
		if (null != jsonObject)
		{
			try
			{
				accessToken = new AccessToken();
				accessToken.setTookenGetTime(Calendar.getInstance().getTimeInMillis());
				accessToken.setToken(jsonObject.getString("access_token"));
				accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
			} catch (JSONException e)
			{
				accessToken = null;
				e.printStackTrace();
				// 获取token失败
				log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
			}
		} else
		{
			log.error("获取token失败 ");
		}
		return accessToken;
	}

	/**
	 * 发起https请求并获取结果
	 * 
	 * @param requestUrl
	 *            请求地址
	 * @param requestMethod
	 *            请求方式（GET、POST）
	 * @param outputStr
	 *            提交的数据
	 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
	 */
	public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr)
	{
		JSONObject jsonObject = null;
		StringBuffer buffer = new StringBuffer();
		try
		{
			// 创建SSLContext对象，并使用我们指定的信任管理器初始化
			TrustManager[] tm = { new MyX509TrustManager() };
			SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
			sslContext.init(null, tm, new java.security.SecureRandom());
			// 从上述SSLContext对象中得到SSLSocketFactory对象
			SSLSocketFactory ssf = sslContext.getSocketFactory();

			URL url = new URL(requestUrl);
			HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
			httpUrlConn.setSSLSocketFactory(ssf);

			httpUrlConn.setDoOutput(true);
			httpUrlConn.setDoInput(true);
			httpUrlConn.setUseCaches(false);
			// 设置请求方式（GET/POST）
			httpUrlConn.setRequestMethod(requestMethod);

			if ("GET".equalsIgnoreCase(requestMethod)) httpUrlConn.connect();

			// 当有数据需要提交时
			if (null != outputStr)
			{
				OutputStream outputStream = httpUrlConn.getOutputStream();
				// 注意编码格式，防止中文乱码
				outputStream.write(outputStr.getBytes("UTF-8"));
				outputStream.close();
			}

			// 将返回的输入流转换成字符串
			InputStream inputStream = httpUrlConn.getInputStream();
			InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
			BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

			String str = null;
			while ((str = bufferedReader.readLine()) != null)
			{
				buffer.append(str);
			}
			bufferedReader.close();
			inputStreamReader.close();
			// 释放资源
			inputStream.close();
			inputStream = null;
			httpUrlConn.disconnect();
			System.out.println(buffer.toString());
			jsonObject = JSONObject.fromObject(buffer.toString());
		} catch (ConnectException ce)
		{
			log.error("Weixin server connection timed out.");
		} catch (Exception e)
		{
			log.error("https request error:{}", e);
		}
		return jsonObject;
	}

	// 菜单创建（POST） 限100（次/天）
	public static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";

	/**
	 * 创建菜单
	 * 
	 * @param menu
	 *            菜单实例
	 * @param accessToken
	 *            有效的access_token
	 * @return 0表示成功，其他值表示失败
	 */
	public static int createMenu(Menu menu, String accessToken)
	{
		int result = 0;

		// 拼装创建菜单的url
		String url = menu_create_url.replace("ACCESS_TOKEN", accessToken);
		// 将菜单对象转换成json字符串
		String jsonMenu = JSONObject.fromObject(menu).toString();
		// 调用接口创建菜单
		JSONObject jsonObject = httpRequest(url, "POST", jsonMenu);

		if (null != jsonObject)
		{
			if (0 != jsonObject.getInt("errcode"))
			{
				result = jsonObject.getInt("errcode");
				log.error("创建菜单失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
			}
		}

		return result;
	}

	public static long getTime(String time)
	{
		return Long.parseLong(time) * 1000l;
	}

	// 上传多媒体文件到微信服务器
	public static final String UPLOAD_MEDIA_URL = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";
	public static final String DOWNLOAD_MEDIA_URL = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID";

	/**
	 * 上传多媒体文件到微信服务器<br>
	 * 
	 * @see http://www.oschina.net/code/snippet_1029535_23824
	 * @see http://mp.weixin.qq.com/wiki/index.php?title=上传下载多媒体文件
	 * 
	 * @author qincd
	 * @date Nov 6, 2014 4:11:22 PM
	 */
	public static JSONObject uploadMediaToWX(String filePath, String type, String accessToken) throws IOException
	{
		File file = new File(filePath);
		if (!file.exists())
		{
			log.error("文件不存在！");
			return null;
		}

		String url = UPLOAD_MEDIA_URL.replace("ACCESS_TOKEN", accessToken).replace("TYPE", type);
		URL urlObj = new URL(url);
		HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
		conn.setDoInput(true);
		conn.setDoOutput(true);
		conn.setUseCaches(false);

		conn.setRequestProperty("Connection", "Keep-Alive");
		conn.setRequestProperty("Charset", "UTF-8");

		// 设置边界
		String BOUNDARY = "----------" + System.currentTimeMillis();
		conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);

		// 请求正文信息

		// 第一部分：
		StringBuilder sb = new StringBuilder();
		sb.append("--"); // ////////必须多两道线
		sb.append(BOUNDARY);
		sb.append("\r\n");
		sb.append("Content-Disposition: form-data;name=\"file\";filename=\"" + file.getName() + "\"\r\n");
		sb.append("Content-Type:application/octet-stream\r\n\r\n");

		byte[] head = sb.toString().getBytes("utf-8");

		// 获得输出流
		OutputStream out = new DataOutputStream(conn.getOutputStream());
		out.write(head);

		// 文件正文部分
		DataInputStream in = new DataInputStream(new FileInputStream(file));
		int bytes = 0;
		byte[] bufferOut = new byte[1024];
		while ((bytes = in.read(bufferOut)) != -1)
		{
			out.write(bufferOut, 0, bytes);
		}
		in.close();

		// 结尾部分
		byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线

		out.write(foot);

		out.flush();
		out.close();

		/**
		 * 读取服务器响应，必须读取,否则提交不成功
		 */
		try
		{
			// 定义BufferedReader输入流来读取URL的响应
			StringBuffer buffer = new StringBuffer();
			BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			String line = null;
			while ((line = reader.readLine()) != null)
			{
				buffer.append(line);
			}

			reader.close();
			conn.disconnect();

			return JSONObject.fromObject(buffer.toString());
		} catch (Exception e)
		{
			log.error("发送POST请求出现异常！" + e);
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 从微信服务器下载多媒体文件
	 * 
	 * @author qincd
	 * @date Nov 6, 2014 4:32:12 PM
	 */
	public static String downloadMediaFromWx(String accessToken, String mediaId, String fileSavePath) throws IOException
	{
		if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(mediaId)) return null;

		String requestUrl = DOWNLOAD_MEDIA_URL.replace("ACCESS_TOKEN", accessToken).replace("MEDIA_ID", mediaId);
		URL url = new URL(requestUrl);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setRequestMethod("GET");
		conn.setDoInput(true);
		conn.setDoOutput(true);
		InputStream in = conn.getInputStream();

		File dir = new File(fileSavePath);
		if (!dir.exists())
		{
			dir.mkdirs();
		}
		if (!fileSavePath.endsWith("/"))
		{
			fileSavePath += "/";
		}

		String ContentDisposition = conn.getHeaderField("Content-disposition");
		String weixinServerFileName = ContentDisposition.substring(ContentDisposition.indexOf("filename") + 10, ContentDisposition.length() - 1);
		fileSavePath += weixinServerFileName;
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fileSavePath));
		byte[] data = new byte[1024];
		int len = -1;

		while ((len = in.read(data)) != -1)
		{
			bos.write(data, 0, len);
		}

		bos.close();
		in.close();
		conn.disconnect();

		return fileSavePath;
	}

	private static final String userInfoURL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + TokenAccessManager.getAccessToken().getToken()
			+ "&openid=OPENID&lang=zh_CN";

	// TODO
	public static UserInfo getUserInfo(String openID)
	{
		UserInfo user = new UserInfo();
		JSONObject userJson = httpRequest(userInfoURL.replace("OPENID", openID), "GET", null);
		int subscribe = userJson.getInt("subscribe");
		boolean isFollow = false;
		switch (subscribe) {
		case 1:
			isFollow = true;
		}
		user.setSubscribe(isFollow);
		user.setOpenID(userJson.getString("openid"));
		user.setNickName(userJson.getString("nickname"));
		user.setSex(userJson.getString("sex"));
		user.setCity(userJson.getString("city"));
		user.setLanguage(userJson.getString("language"));
		user.setProvince(userJson.getString("province"));
		user.setCountry(userJson.getString("country"));
		user.setHeadimgurl(userJson.getString("headimgurl"));
		user.setSubscribe_time(getTime(userJson.getString("subscribe_time")));
		// user.setUnionid(userJson.getString("unionid"));
		return user;
	}

	public static final String sendKFMessageURL = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=";

	/**
	 * 客服消息接口
	 * 
	 * @param args
	 */
	public static void sendMessageFromKF(JSONBaseMessage message)
	{
		String url = sendKFMessageURL + TokenAccessManager.getAccessToken().getToken();
		try
		{
			System.out.println(url);
			String json = HttpRequestUtil.sendPost(url, MessageUtil.baseMessageToJson(message));
		} catch (Exception e)
		{
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		
	}

	public static void main(String[] args)
	{
		JSONNewsMessage jnm = new JSONNewsMessage();
		JsonArticle ja = new JsonArticle();
		ja.setDescription("测试");
		ja.setPicUrl("https://res.wx.qq.com/mpres/htmledition/images/advanced/dev_code22921f.jpg");
		ja.setTitle("图文消息推送");
		ja.setUrl("http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html");
		List<JsonArticle> list = new ArrayList<JsonArticle>();
		list.add(ja);
		jnm.setArtiles(list);
		jnm.setTouser("ockDjsvmMDd_NnUk90nU4zGY-JuQ");
		sendMessageFromKF(jnm);
	}
	
}